// Server.h
// (c) 2008, Charles Lechasseur
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef RRO_UTILS_COM_SERVER_H
#define RRO_UTILS_COM_SERVER_H

#pragma once

#include "Locks/CriticalSection.h"
#include "Exceptions/Exception.h"
#include "COM/AutoPtr.h"
#include "COM/ClassFactory.h"
#include <memory>
#include <map>
#include <memory.h>
#include <windows.h>

#pragma warning( push )
#pragma warning( disable : 4290 )   // C++ exception specification not supported


namespace RRO {
namespace COM
{
    // Forward declaration.
    // (NOTE: this should not be needed, but for some obscure reason, it doesn't compile if
    // it's not there. If anybody understands how to fix such a compilation bug, do so... -clechasseur)
    class ClassFactory;

    //
    // Exception thrown from Server when server is asked to remove an object that isn't supposed to exist.
    //
    class InvalidObjectCountException : public Exception
    {
    public:
                                        InvalidObjectCountException(void);
                                        InvalidObjectCountException(const InvalidObjectCountException& p_Exception);
        InvalidObjectCountException&    operator=(const InvalidObjectCountException& p_Exception);
        virtual                         ~InvalidObjectCountException(void);

        virtual const char*             what(void) const;
    };

    //
    // Map type to store a list of class factories.
    //
    typedef std::map<CLSID, AutoPtr<ClassFactory> > ClassFactoryMap;

    //
    // COM server class
    //
    // Singleton designed to implement some of the work of a COM server, like registering class factories,
    // providing implementations of standard COM DLL functions, maintaining object count, etc.
    //
    class Server
    {
    public:
        virtual                                     ~Server(void);

        static Server&                              Instance();

        void                                        AddObject(void);
        void                                        RemoveObject(void) throw(InvalidObjectCountException);
        unsigned long                               ObjectCount(void) const;
        bool                                        CanClose(void) const;

        void                                        RegisterFactory(ClassFactory* p_pFactory);
        ClassFactory*                               FindFactory(const CLSID& p_ClassID) const;

        void                                        RegisterServer(void);
        void                                        UnregisterServer(void);

    private:
                                                    Server(void);

        static CriticalSection                      s_ServerLock;
        static std::auto_ptr<Server>                s_Server;

        unsigned long                               m_ObjectCount;

        ClassFactoryMap                             m_Factories;

        // THESE METHODS ARE NOT IMPLEMENTED.
                                        Server(const Server&);
        Server&                         operator=(const Server&);
    };

}; // namespace COM
}; // namespace RRO

// This must be outside our namespaces to be used by less<>.
bool operator<(const CLSID& p_Left, const CLSID& p_Right);

// Methods implemented by an in-proc COM server. Uses the Server class.
STDAPI DllRegisterServer(void);
STDAPI DllUnregisterServer(void);
STDAPI DllGetClassObject(REFCLSID p_ClassID, REFIID p_IID, void** p_ppObject);
STDAPI DllCanUnloadNow(void);


#pragma warning( pop )

#endif RRO_UTILS_COM_SERVER_H
